/*
 * @(#)DmsCreatePaperShortcut.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.workflow.action;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.quartz.JobDataMap;

import com.dcivision.dms.bean.DmsDocument;
import com.dcivision.dms.core.DocumentOperationManager;
import com.dcivision.dms.core.DocumentRetrievalManager;
import com.dcivision.dms.core.RootRetrievalManager;
import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.ErrorConstant;
import com.dcivision.framework.EventLogger;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemFunctionConstant;
import com.dcivision.framework.Utility;
import com.dcivision.user.bean.UserRecord;
import com.dcivision.user.dao.UserRecordDAObject;
import com.dcivision.workflow.WorkflowErrorConstant;
import com.dcivision.workflow.bean.MtmWfProgressWfProgress;
import com.dcivision.workflow.bean.MtmWorkflowDynamicUserActor;
import com.dcivision.workflow.bean.MtmWorkflowStepUserActor;
import com.dcivision.workflow.bean.WorkflowProgress;
import com.dcivision.workflow.core.WorkflowProcessor;
import com.dcivision.workflow.dao.MtmWfProgressWfProgressDAObject;
import com.dcivision.workflow.dao.MtmWorkflowDynamicUserActorDAObject;
import com.dcivision.workflow.dao.MtmWorkflowStepUserActorDAObject;
import com.dcivision.workflow.dao.WorkflowProgressDAObject;

/**
 *  DmsCreatePaperShortcut.java
 *
 *  This class is the automatic task handler for publish paper document.
 *
 *  @author      Lun Au
 *  @company     DCIVision Limited
 *  @creation date   10/11/2004
 *  @version     $Revision: 1.15.2.2 $
 */
public class DmsMovePaperDocument extends com.dcivision.workflow.core.WorkflowProcessor {

  public static final String REVISION = "$Revision: 1.15.2.2 $";

  public DmsMovePaperDocument() {
    this.numOfRoutine = 1;
    this.labelType = WorkflowProcessor.LABEL_TYPE_USER_DEFINE;
    this.labelString = new String[] {"workflow.label.step_status_G"};
  }

  /**
   * 1. Create a shortcut to the paper document in the original location
   * 2. Move the original paper document to the personal folder of action taker
   */
  public synchronized void execute(JobDataMap dataMap, WorkflowProgress currentProgress) throws ApplicationException {
    log.info("***** DmsMovePaperDocument workflow processor BEGIN *****");
    Connection conn = null;

    Integer trigerEventUserID = new Integer(0);
    String serverName = "127.0.0.1";
    String functionName = SystemFunctionConstant.WORKFLOW_TASK;
    String errorMessage = "";

    try {
      //* get the DB Connection
      SessionContainer sessionContainer = this.getSessionContainer();

      /*************************************************************
       *  get Event Log Information Begin
       *************************************************************/
      if (!Utility.isEmpty(sessionContainer.getUserRecordID())) {
        trigerEventUserID = sessionContainer.getUserRecordID();
      }

      if (!Utility.isEmpty(sessionContainer.getUserIPAddress())) {
        serverName = sessionContainer.getUserIPAddress();
      }
      errorMessage =  "DmsMovePaperDocument.java -- Track ID: " + currentProgress.getTrackID() +
                      ", Workflow Progress ID : " + currentProgress.getID() +
                      ", Workflow Step ID: " + currentProgress.getWorkflowStepID() +
                      "<br> ";

      /*************************************************************
       *  get Event Log Information End
       *************************************************************/
      //for schedule job useing the processer connection.
      isLocalConnection = false;
      if(!Utility.isEmpty(this.getConnection())){
        conn = this.getConnection();
      }else{
        isLocalConnection = true;
        conn = DataSourceFactory.getConnection();
      }
      sessionContainer.setByPassPermission(true);

      //* create required DAObject and Manager
      WorkflowProgressDAObject progressDAO = new WorkflowProgressDAObject(sessionContainer, conn);
      MtmWorkflowStepUserActorDAObject stepActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, conn);
      DocumentOperationManager docOperationManager = new DocumentOperationManager(sessionContainer, conn);
      DocumentRetrievalManager docRetrievalManager = new DocumentRetrievalManager ( sessionContainer, conn );
      RootRetrievalManager rootRetrievalManager = new RootRetrievalManager ( sessionContainer, conn );
      MtmWfProgressWfProgressDAObject mtmWfProgressWfProgressDAO = new MtmWfProgressWfProgressDAObject(sessionContainer, conn);
      WorkflowProgress prevProgress = new WorkflowProgress();
      //* get relevant information from
      /*
      Integer trackID = currentProgress.getTrackID();
      log.info("track id: "+trackID);
      List progressList = progressDAO.getListByTrackID(trackID);
      log.info("progress list size: "+ progressList.size());
      int curProgressSeqNo = currentProgress.getSeqNo().intValue();
      log.info("current progress seq no: "+curProgressSeqNo);
      WorkflowProgress prevProgress = (WorkflowProgress) progressList.get((curProgressSeqNo-1)-1);
      */
      // ADD BY DICK
      // TODO get pre progress through MTM_WF_PROGRESS_WF_PROGRESS
      List parentProgressList = mtmWfProgressWfProgressDAO.getListByChildProgressID(currentProgress.getID());
      if (!Utility.isEmpty(parentProgressList)) {
        MtmWfProgressWfProgress mtmWfProgressWfProgress = (MtmWfProgressWfProgress)parentProgressList.get(parentProgressList.size()-1);
        prevProgress = (WorkflowProgress)progressDAO.getObjectByID(mtmWfProgressWfProgress.getParentProgressID());
      }
      // END BY DICK
      log.info("previous progress id: " + prevProgress.getID());
      Integer userRecordID = prevProgress.getUpdaterID();
      log.info("user record id: "+userRecordID);

      //* get relevant information from
      DmsDocument paperDocument = (DmsDocument) dataMap.get("WORKFLOW_OBJECT");
      log.debug("workflow object class name: "+paperDocument.getClass().getName());

      // loop through the userActorList to check if there is dynamic assign owner,
      // also assume there are already runtime assigned records in the
      // table MTM_WF_DYNAMIC_USER_ACTOR
      List tmpUserActorList = new ArrayList();
      List userActorList = stepActorDAO.getListByWorkflowStepID(prevProgress.getWorkflowStepID());
      Iterator userActorItr = userActorList.iterator();
      while ( userActorItr.hasNext() ) {
        MtmWorkflowStepUserActor userActor = (MtmWorkflowStepUserActor)userActorItr.next();
        if ( MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN.equals(userActor.getActorType()) ) {
          MtmWorkflowDynamicUserActorDAObject dynamicActorDAO = new MtmWorkflowDynamicUserActorDAObject ( sessionContainer, conn );
          List dynamicActors = dynamicActorDAO.getListByWorkflowProgressID ( prevProgress.getID() ) ;
          if ( dynamicActors.size() == 0 ) {
            // if there is no runtime assigned owner
            // use the "Dynamic Assigned" string
            //tmpUserActorList.add ( userActor );
            break;
          } else {
            //userActorList = new ArrayList();
            Iterator dynamicActorItr = dynamicActors.iterator();
            while ( dynamicActorItr.hasNext() ) {
              // TODO: modify MtmWorkflowDynamicUserActor to extends MtmWorkflowStepUserActor
              MtmWorkflowDynamicUserActor dynamicActor = (MtmWorkflowDynamicUserActor)dynamicActorItr.next();
              MtmWorkflowStepUserActor tmpUserActor = new MtmWorkflowStepUserActor();
              tmpUserActor.setWorkflowStepID ( prevProgress.getWorkflowStepID() );
              tmpUserActor.setActorType ( dynamicActor.getActorType() );
              tmpUserActor.setActorID ( dynamicActor.getActorID() );
              tmpUserActor.setActorName ( dynamicActor.getActorName() );
              tmpUserActorList.add ( tmpUserActor );
            }
          }
        }
      }
      if ( tmpUserActorList.size() > 0 ) {
        // if there are already runtime assigned owners
        userActorList = null;
        userActorList = tmpUserActorList;
      }

      // Check the owners of previous step, if assigned to user/group/role, should
      // move the original to appropriate home folder (personal folder for user type)
      // If there are multiple owners assigned (for example, Role 1 and Role 2) and
      // the action taker belongs to both role, take the first one. If there are no
      // dynamic assigned owner, use the actionTaker.
      DmsDocument homeFolder = null;
      if ( userActorList.size() == 0 ) {
        // Move the original paper document to the last action taker's personal folder
        Integer rootID = rootRetrievalManager.getRootObjectByOwnerID(userRecordID).getID();
        homeFolder = rootRetrievalManager.getRootDocument(rootID);
        if ( homeFolder != null && log.isDebugEnabled() ) {
          log.debug("Move the original document to user["+userRecordID+"], folder["+homeFolder.getID()+"], root["+homeFolder.getRootID()+"]");
        }
      } else {
        userActorItr = userActorList.iterator();
        while ( userActorItr.hasNext() ) {
          MtmWorkflowStepUserActor userActor = (MtmWorkflowStepUserActor)userActorItr.next();
          if ( MtmWorkflowStepUserActor.ACTOR_TYPE_USER.equals(userActor.getActorType()) ) {
            // It is assigned to user owner, move to user home folder
            // TODO: check if userRecordID==userActor.getActorID()
            Integer rootID = rootRetrievalManager.getRootObjectByOwnerID(userActor.getActorID()).getID();
            homeFolder = rootRetrievalManager.getRootDocument(rootID) ;
            if ( homeFolder != null && log.isDebugEnabled() ) {
              log.debug("Move the original document to user["+userActor.getActorID()+"], folder["+homeFolder.getID()+"], root["+homeFolder.getRootID()+"]");
            }
          } else if ( MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP.equals(userActor.getActorType()) ) {
            // It is assigned to group owner, move to group home folder
            // TODO: check if userRecordID belongs to this Group
            homeFolder = docRetrievalManager.getHomeFolderByObjectTypeAndID(MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP, userActor.getActorID());
            if ( homeFolder != null && log.isDebugEnabled() ) {
              log.debug("Move the original document to group["+userActor.getActorID()+"], folder["+homeFolder.getID()+"], root["+homeFolder.getRootID()+"]");
            }
          } else if ( MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE.equals(userActor.getActorType()) ) {
            // It is assigned to role owner, move to role home folder
            // TODO: check if userRecordID belongs to this Role
            homeFolder = docRetrievalManager.getHomeFolderByObjectTypeAndID(MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE, userActor.getActorID());
            if ( homeFolder != null && log.isDebugEnabled() ) {
              log.debug("Move the original document to role["+userActor.getActorID()+"], folder["+homeFolder.getID()+"], root["+homeFolder.getRootID()+"]");
            }
          }
          if ( homeFolder != null ) {
            // We've already got the home folder, leave now
            break;
          }
        }
      }
      if ( homeFolder == null ) {
        Integer rootID = rootRetrievalManager.getRootObjectByOwnerID(userRecordID).getID();
        homeFolder = rootRetrievalManager.getRootDocument(rootID);
        if ( homeFolder != null && log.isDebugEnabled() ) {
          log.debug("Move the original document to user["+userRecordID+"], folder["+homeFolder.getID()+"], root["+homeFolder.getRootID()+"]");
        }
      }

      // Prepare the SessionContainer object that
      UserRecordDAObject userRecordDAO = new UserRecordDAObject(sessionContainer, conn);
      UserRecord userRecord = (UserRecord) userRecordDAO.getObjectByID(userRecordID);
      sessionContainer.setUserRecord(userRecord);
      //* get relevant information from
      Map objParamMap = (Map) dataMap.get("OBJECT_PARAMETER");
      log.debug("object parameter map: "+objParamMap);
      sessionContainer.setUserIPAddress("localhost");

      docOperationManager = new DocumentOperationManager(sessionContainer, conn);
      synchronized (docOperationManager) {
        try{
          docOperationManager.createWFPaperDocShortCut(paperDocument);
        } catch ( ApplicationException ae ) {
          // ignore
          log.error(ae, ae);
        }
      }
      synchronized (docOperationManager) {
        if ( paperDocument.getParentID().intValue() != homeFolder.getID().intValue() ) {
          // Get the paperDocument once again to avoid concurrent update problem
          // Because moveDocument function will check for updateCount to detect concurrent update
          paperDocument = docRetrievalManager.getDocumentByID(paperDocument.getID());
          docOperationManager.moveDocument(paperDocument, homeFolder, homeFolder.getRootID());
        }
      }
      if(isLocalConnection){
        conn.commit();
      }
    } catch (ApplicationException appEx) {
      log.error(appEx.getMsgCode(), appEx);
      /***********************************
       *  Record the Event Log.
       ***********************************/
      EventLogger.logEventMessage(trigerEventUserID, serverName, errorMessage, appEx.getMsgCode(), WorkflowErrorConstant.LOG_AUTO_TASK_ERROR_CODE, functionName, appEx.toString() );

      throw appEx; //* prop
    } catch (Exception e) {
      log.error("Error during processing this automatic task.", e);
      /***********************************
       *  Record the Event Log.
       ***********************************/
      EventLogger.logEventMessage(trigerEventUserID, serverName, errorMessage, ErrorConstant.COMMON_FATAL_ERROR, WorkflowErrorConstant.LOG_AUTO_TASK_ERROR_CODE, functionName, e.toString() );

      throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR); //* throw an applicationExcpetion with an appropriate
    } finally {
      if(isLocalConnection){
        try { conn.close(); } catch (Exception ignore) {} finally { conn = null; }
      }
    }
    log.info("***** DmsMovePaperDocument workflow processor END   *****");
  }

}
